﻿using System;
using System.Diagnostics;
using GMPP.utils;
using VLIB28D.Geometry3D;

namespace GMPP
{
    public class CameraControl
    {
        private static float bound = 0.5f;
        private Point3D _cameraLoc = new Point3D();
        private float _viewDistance;
        private Point3D _viewPort = new Point3D();

        public CollisionSphere Cs
        {
            get { return new CollisionSphere(bound, _cameraLoc); }
        }

        public CameraControl(Point3D cl, Point3D vp, Vector3D up)
        {
            _cameraLoc = cl;
            _viewPort = vp;
             
        }

        #region 控制方法

        /// <summary>
        ///     镜头前后平移
        /// </summary>
        /// <param name="dis">此值为正前移，为负后移</param>
        public void MoveForwardOrBack(float dis)
        {
            var ve = new Vector3D(WatchDirection.X, 0, WatchDirection.Z);
            _viewPort = _viewPort + dis * (ve.UnitVector);
            _cameraLoc = _cameraLoc + dis * (ve.UnitVector);

        }

        /// <summary>
        ///     镜头左右平移
        /// </summary>
        /// <param name="dis">此值为正左移，为负右移</param>
        public void MoveLeftOrRight(float dis)
        {
            var ve = new Vector3D(WatchDirection.X, 0, WatchDirection.Z);
            var Y = new Vector3D(0, 1, 0);
            Vector3D moveLeft = Vector3D.CrossProduct(Y, ve);
            _cameraLoc = _cameraLoc + dis * (moveLeft.UnitVector);
            _viewPort = _viewPort + dis * (moveLeft.UnitVector);

        }


        /// <summary>
        ///     镜头上下平移
        /// </summary>
        /// <param name="dis">此值为正上移，为负下移</param>
        public void MoveUpOrDown(float dis)
        {
            _cameraLoc.Y += dis;
            _viewPort.Y = dis;

        }

        public void ZoomIn(float ratio)
        {

            _cameraLoc = _cameraLoc + ratio * (-WatchDirection.UnitVector);

        }

        public void ZoomOut(float ratio)
        {
            if (ViewDistance > ratio)
            {
                _cameraLoc = _cameraLoc + ratio * (WatchDirection.UnitVector);
            }
        }


        public void LocatTo(Point3D pt)
        {
            _viewPort = pt;
            _cameraLoc = _viewPort + ViewDistance * (-WatchDirection.UnitVector);

        }

        public void RatateHorizontal(float angle)
        {
            var watchVe = WatchDirection;
            watchVe.phi += angle;
            _cameraLoc = _viewPort + ViewDistance * (-watchVe.UnitVector);
        }



        public void RatateVertical(float angle)
        {
            var watchVe = WatchDirection;

            if (watchVe.theta + angle < Math.PI && watchVe.theta + angle > 0)
            {
                watchVe.theta += angle;
            }

            _cameraLoc = _viewPort + ViewDistance * (-watchVe.UnitVector);
        }

        #endregion

        public Point3D ViewPort
        {
            get { return _viewPort; }
            set
            {
                _viewPort = value;

            }
        }

        public Point3D CameraLoc
        {
            get { return _cameraLoc; }
            set
            {
                _cameraLoc = value;

            }
        }

        public Vector3D WatchDirection
        {
            get
            {
                return new Vector3D(CameraLoc, ViewPort);
            }
        }


        public float ViewDistance
        {
            get { return (float)WatchDirection.Length; }
        }

        public override string ToString()
        {
            var str = "Locat:" + _cameraLoc.X.ToString() + "," + _cameraLoc.Y.ToString() + "," + _cameraLoc.Z.ToString() +
                      "\n"
                      + "LookAt:" + _viewPort.X.ToString() + "," + _viewPort.Y.ToString() + "," + _viewPort.Z.ToString() +
                      "\n\n";
            return str;
        }
    }
}